<?php

namespace app\common\logic;

use app\admin\model\Admin;
use app\common\job\CancelOrderJob;
use app\common\library\exception\ApiException;
use app\common\library\Helper\DateTime;
use app\common\library\MemberVo;
use app\common\model\Agent;
use app\common\model\Car;
use app\common\model\Config;
use app\common\model\Coupon;
use app\common\model\FreezeRecord;
use app\common\model\Member;
use app\common\model\MoneyRecord;
use app\common\model\Order;
use app\common\model\OrderAftersales;
use app\common\model\OrderAftersalesRecord;
use app\common\model\OrderComment;
use app\common\model\OrderCommission;
use app\common\model\PayLog;
use app\common\model\ServiceTimes;
use app\common\model\Shop;
use app\common\model\ShopGoods;
use app\common\model\ShopMember;
use app\common\resourceHandle\OrderResource;
use app\job\Clue;
use app\job\Message;
use EasyWeChat\Factory;
use Endroid\QrCode\Color\Color;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelLow;
use Endroid\QrCode\Logo\Logo;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeMargin;
use Endroid\QrCode\Writer\PngWriter;
use think\Cache;
use function tests\thinkphp\library\think\func_trim;
use think\Db;
use think\db\Query;
use think\Env;
use think\Exception;
use think\Log;
use think\Queue;

class OrderLogic extends BaseLogic
{
    public $model;

    public $resourceHandle;

    public function assignModel()
    {
        /** @var Order $model */
        $this->model          = new Order();
        $this->resourceHandle = new OrderResource();
    }

    public function handleSearch(Query $query, array $params): Query
    {
        if (isset($params['shop_id'])) {
            $query->where('order.shop_id', $params['shop_id']);
        }

        if (isset($params['member_id'])) {
            $query->where('order.member_id', $params['member_id']);
        }

        if (isset($params['keyword']) && !empty($params['keyword'])) {

            $whereOrRaw = "order.order_sn  LIKE '%{$params['keyword']}%' or car.car_numbers  LIKE '%{$params['keyword']}%'";
            $query->where($whereOrRaw);
        }

        if (isset($params['order_sn'])) {
            $query->where('order.order_sn', 'like', "%" . $params['order_sn'] . "%");
        }

        if (isset($params['date']) && !empty($params['date'])) {
            $timeZone = DateTime::toTimestamp('rangeMonthByDate', $params['date']);
            $query->whereBetween('order.createtime', $timeZone);
        }

        if (isset($params['order_status']) && !empty($params['order_status'])) {
            $query->where('order.order_status', $params['order_status']);
        } else {
            $query->where('order.order_status', '>', 0);
        }

        if (isset($params['status_in']) && !empty($params['status_in'])) {
            $query->whereIn('order.order_status', $params['status_in']);
        }
        if (isset($params['bill_id'])) {
            $query->where('order.bill_id', $params['bill_id']);
        }
        if (isset($params['pay_amount']) && !empty($params['pay_amount'])) {
            $query->where('order.pay_amount', '>',0);
        }
        if (isset($params['id']) && !empty($params['id'])) {
            $query->where('order.id', $params['id']);
        }
        return $query;
    }

    // 订单存在判断
    public function orderExist($orderId)
    {
        $order = Order::getOrderById($orderId, $this->memberId);
        if (empty($order)) throw new ApiException('订单不存在',404);
        return $order;
    }

    /**
     * 订单列表
     * @param array $params
     * @return \think\Paginator
     * @throws \think\exception\DbException
     */
    public function index(array $params)
    {
        $params['field'] = "id,order_sn,shop_id,member_id,order_amount,order_status,payment_time,audit_time,cancel_time,createtime,pay_amount,expires_time";
        $params['with'] = ['orderGoods', 'car','shop','aftersalesc'];
        if (MemberVo::instance()->getShopId() == 0)
            $params['member_id'] = MemberVo::instance()->getMemberId();
        $params['orderBy'] = 'order.id';
        $params['orderType'] = 'desc';
        return $this->getPageList($params)->each(function (&$item){
            $item['createtime'] = $item['createtime'] * 1000;
            $item['shop_name'] = $item['shop']['shop_name'];
            $item['car_numbers'] = $item['car']['car_numbers'];
            $item['after_status'] = 0;
            if ($item['order_status'] == 5){
                $item['after_status'] = $item['aftersalesc']['status'];
            }
            unset($item['shop'],$item['car'],$item['aftersalesc']);
            return $item;
        });
//        echo $this->model->getLastSql();die;
//        return $list;

    }

    /**
     * 待开发票订单列表
     * @param array $params
     * @return \think\Paginator
     * @throws \think\exception\DbException
     */
    public function waitOpenBillOrders(array $params)
    {
        $params['with'] = ['orderGoods','shop'];
        $params['field'] = "id,shop_id,createtime,pay_amount";
        $params['orderBy'] = 'order.id';
        $params['orderType'] = 'desc';
        return $this->getPageList($params)->each(function (&$item){
            $item['createtime'] = date('Y-m-d H:i:s',$item['createtime']);
            $item['goods_name'] = $item['order_goods'][0]['goods_name'];
            unset($item['order_goods'],$item['shop']);
            return $item;
        });
    }

    /**
     * 订单确认
     * @param array $params
     * @return \think\Paginator
     * @throws \think\exception\DbException
     */
    public function order_confirm(array $params)
    {
        $goods_info = ShopGoods::get(['goods_id'=>$params['goods_id'],'shop_id'=>$params['shop_id']],['goods','shop']); //获取该订单信息
        $price_info = ShopGoods::getPrice($goods_info['market_price']);//价格
        //获取优惠券可用数量
        $coupon_list = Coupon::field('id,money,begin_time,end_time,least_cost')->where(['coupon.status'=>1,'coupon.member_id'=>MemberVo::instance()->getMemberId(),'coupon.least_cost'=>['<=',$price_info['price']],'coupon.begin_time'=>['lt',time()],'coupon.end_time'=>['gt',time()]])->with('couponSetting')->order('money desc')->select()->each(function (&$item){
            $item['name'] = $item['coupon_setting']['name'];
            $item['begin_time'] = date('Y.m.d',$item['begin_time']);
            $item['end_time'] = date('Y.m.d', $item['end_time']);
//            $item['desc'] = htmlspecialchars_decode($item['coupon_setting']['remark']);
            $item['desc'] = $item['least_cost'] == 0 ? "无门槛" : "满{$item['least_cost']}元可用";
            unset($item['coupon_setting']);
            return $item;
        });
        $member_info = Member::get(MemberVo::instance()->getMemberId());//获取用户信息

        //获取车牌列表
        $car_list = Car::field('id,car_numbers')->where(['member_id'=>MemberVo::instance()->getMemberId(),'is_del'=>0])->order('is_default desc')->select();
        return [
            'goods_id'=>$goods_info['goods_id'],
            'cover_img'=>$goods_info['goods']['cover_img'],
            'shop_id'=>$goods_info['shop_id'],
            'price'=>$price_info['price'],
            'price_tip'=>$price_info['price_tip'],
            'num'=>1,
            'goods_name'=>$goods_info['goods']['goods_name'],
            'shop_name'=>$goods_info['shop']['shop_name'],
            'member_name'=>$member_info['member_name'],
            'member_mobile'=>$member_info['member_mobile'],
            'coupon_num'=>count($coupon_list),
            'coupon_list'=>$coupon_list,
            'car_list'=>$car_list,
            'money'=>$price_info['price'],
            'discount_money'=>'0.00',
            'member_equity' =>['过期退','过期自动退','到店服务']
        ];


    }


    /**
     * 订单详情
     * @param array $params
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function detail(array $params)
    {
        if (isset($params['member_id']) && !empty($params['member_id'])){
            $order = Order::field('id,order_sn,member_id,order_amount,bill_id,order_status,payment_time,audit_code,pay_amount,coupon_id,coupon_money,pay_type,expires_time,createtime')->where(['order.id'=>$params['order_id'],'order.member_id'=>$params['member_id']])->with(['orderGoods', 'car','shop','coupon','aftersalesc'])->find();
        }else{
            $order = Order::field('id,order_sn,member_id,order_amount,bill_id,order_status,payment_time,audit_code,pay_amount,coupon_id,coupon_money,pay_type,expires_time,createtime')->where(['order.id'=>$params['order_id'],'order.shop_id'=>MemberVo::instance()->getShopId()])->with(['orderGoods', 'car','shop','coupon','aftersalesc'])->find();
        }
        if (!$order)
            throw new ApiException('订单不存在',404);
        $order['car_numbers'] = $order['car']['car_numbers'];
        $order['shop_name'] = $order['shop']['shop_name'];
        $order['coupon_name'] = '';
        $order['createtime'] = $order['createtime'] *1000;
        $order['audit_qrcode'] = Env::get('app.app_host').'/uploads/order_qrcode/'.md5($order['audit_code']).'.png'; //核销二维码
        if ($order['coupon_id'] > 0){
            $coupon_info = Coupon::where('coupon.id',$order['coupon_id'])->with('couponSetting')->find();
            $order['coupon_name'] = $coupon_info['couponSetting']['name'];
        }
        $order['after_status'] = 0;
        if ($order['order_status'] == 5){
            $order['after_status'] = $order['aftersalesc']['status'];
        }
        $order['comment'] = [];
        if ($order['order_status'] == 4 ){
            $comment = OrderComment::get(['order_id'=>$order['id']],['commentImage', 'member' => function ($query) {
                $query->field(['id', 'member_avatar', 'member_name']);
            }]);
            $comment['images'] = array_column($comment->comment_image->toArray(),'image');
            $comment['member_name'] = star_str($comment['member']['member_name']);
//            $item['member_avatar'] = $item['member']['member_avatar'];
            unset($comment->comment_image,$comment['member'],$comment['shop_id'],$comment['updatetime'],$comment['deletetime'],$comment['shop_goods_id'],$comment['shop_id'],$comment['anonymous'],$comment['member_id'],$comment['order_id']);
            $order['comment'] = $comment;
        }
        $order['refund'] = [];
        if ($order['order_status'] == 5 && $order['after_status'] == 3){
            $refund['money'] = $order['aftersalesc']['refund'] ?? '';//退款金额
            $refund['time'] = $order['aftersalesc']['updatetime'] ?? '';//到账时间
            $refund['pay_type'] = $order['aftersalesc']['pay_type'] ?? '';//支付方式：1、微信支付 2、余额支付
            $order['refund'] = $refund;
        }
        unset($order['car'],$order['shop'],$order['coupon'],$order['aftersalesc']);
        return $order;
    }


    /**
     * 提交订单
     * @param array $params
     * @return string
     * @throws ApiException
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function submit(array $params)
    {
        Db::startTrans();
        try{
            // 车辆
            $car = model('car')->find($params['car_id']);
            if (empty($car))
                throw new Exception('车辆不存在');
            $info = $this->calculate($params);
            //获取商铺代理商id
            $shop = Shop::get($params['shop_id']);
            if (empty($shop))
                throw new Exception('店铺信息不存在');
            if ($shop['audit_status'] != 1)
                throw new Exception('该店铺暂时不支持下单');
            if ($shop['is_del'] === 1)
                throw new Exception('该店铺已被删除');
            if ($shop['status'] === 0)
                throw new Exception('该店铺已被关闭');
            $agent = Agent::get($shop['agent_id']);
            $audit_code = Order::generateAuditCode();
            $order_sn = Order::generateOrderSn();
            // 写入订单
            $order = $this->model->create([
                'order_sn'     => $order_sn,
                'member_id'    => $this->memberId,
                'shop_id'      => $params['shop_id'],
                'coupon_id'    => $params['coupon_id'] ?? 0,
                'car_id'       => $params['car_id'],
                'coupon_money' => $info['coupon_amount'],
                'contact'      => $params['contact'],
                'agent_id'      =>$shop['agent_id'],
                'mobile'       => $params['mobile'],
                'pay_amount'   => $info['money'],
                'order_amount' => $info['order_amount'],
                'shop_cost'    => $info['goods_info']['cost'],
                'openid'       => $this->openid,
                'audit_code'     => $audit_code,
                'cost'=>        $info['goods_info']['cost'],
                'order_status' => Order::ORDER_STATUS_WAIT_PAY,
                'ratio' => $agent['ratio'],
            ]);
            // 写入订单商品
            $goodsData = [
                'goods_id'        => $info['goods_info']['goods_id'],
                'shop_id'         => $params['shop_id'],
                'member_id'       => $this->memberId,
                'goods_name'      => $info['goods_info']['goods']['goods_name'],
                'goods_image'      => $info['goods_info']['goods']['cover_img'],
                'goods_price'     => $info['goods_info']['price'],
                'goods_num'       => 1,
                'goods_pay_price' => $info['goods_info']['price'],
            ];
            $order->orderGoods()->saveAll([$goodsData]);
            if ($params['coupon_id']){ //设置优惠券被使用
                Coupon::update(['status'=>2],['id'=>$params['coupon_id'],'member_id'=>MemberVo::instance()->getMemberId()]);
            }
            //生成二维码
            $this->mkCode(Env::get('app.app_host').'/order/detail?audit_code='.$audit_code,md5($audit_code));

            //        // 取消订单延时队列
//        (new CancelOrderJob($order))
//            ->delay(Order::PAYMENT_TIMEOUT)
//            ->dispatch();
            Db::commit();
            return $order->id;
        }catch (Exception $e){
            Db::rollback();
            throw new ApiException($e->getMessage(),404);
        }
    }

    /**
     * 取消订单
     * @param Order $order
     * @return array|bool|float|int|mixed|object|\stdClass|null
     * @throws ApiException
     */
    public function cancelOrder(Order $order)
    {
        Db::startTrans();

        try {
            if ((int)$order->order_status !== Order::ORDER_STATUS_WAIT_PAY)
                throw new ApiException('订单状态错误',404);
            $order->order_status = Order::ORDER_STATUS_CANCEL;
            $order->cancel_time  = time();
            $order->save();
            if ($order->coupon_id > 0){
                Coupon::update(['status'=>1],['id'=>$order->coupon_id]);
            }
            //如果是否组合支付
            /*if ($order->pay_type == Order::PAY_TYPE_WECHAT_AND_BALANCE){
                $freezeInfo = FreezeRecord::get(['status'=>1,'order_id'=>$order->id,'member_id'=>$order->member_id]);//冻结信息
                if (!empty($freezeInfo)){
                    $freezeInfo->status = 2;//解除金额冻结
                    //获取用户余额
                    $member = Member::get($order->member_id);
                    if ($member->discount > $freezeInfo->discount){//如果优惠金额比目前低，则更新
                        $member->discount = $freezeInfo->discount;
                    }
                    $member->balance = bcadd($member->balance,$freezeInfo->money,2);//余额加回去
                    $member->save();
                    $freezeInfo->save();
                }
            }*/
            Db::commit();
            return $order->id;
        } catch (\Throwable $e) {
            Db::rollback();

            if ($e instanceof ApiException) {
                throw $e;
            }

            Log::error($e->getMessage());

            throw new ApiException('取消订单失败',404);
        }
    }

    /**
     * 支付订单
     * @param $orderId
     * @param $payType
     * @return array|string|void
     * @throws ApiException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function payOrder($orderId, $payType)
    {
        $order = $this->model->lock(true)->where('openid', $this->openid)->find($orderId);
        if (empty($order))
            throw new ApiException('订单不存在',404);
        $shop = Shop::get($order['shop_id']);
        if (empty($shop))
            throw new ApiException('店铺信息不存在',404);
        if ($shop['is_del'] === 1)
            throw new ApiException('该店铺已被删除',404);
        if ($shop['status'] === 0)
            throw new ApiException('该店铺已被关闭',404);

        if ($payType === Order::PAY_TYPE_WECHAT){//微信支付
            $order_cache = Cache::store('redis')->get('order_id_'.$orderId);
            if ($order_cache)
                throw new ApiException('订单支付中请勿重复点击',404);
            Cache::store('redis')->set('order_id_'.$orderId,1,5);
            $res = $this->payWechat($order);
        }elseif ($payType === Order::PAY_TYPE_WECHAT_AND_BALANCE){ //组合支付
            $order_cache = Cache::store('redis')->get('order_id_'.$orderId);
            if ($order_cache)
                throw new ApiException('订单支付中请勿重复点击',404);
            Cache::store('redis')->set('order_id_'.$orderId,1,5);
            $res = $this->payWechatAndBalance($order);
        }else{//余额支付
            $res = $this->payBalance($order);
        }
        if ($res === false)
            throw new ApiException('支付失败',404);
        return $res;
    }

    /**
     * 微信支付
     * @param Order $order
     * @return array|string
     * @throws ApiException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function payWechat(Order $order)
    {
        if ($order->order_status !== Order::ORDER_STATUS_WAIT_PAY)
            throw new ApiException('订单状态错误',404);
        // 需重新计算订单金额
        $order->pay_amount = $this->calculateByPayType($order)['pay_amount'];
        $order->order_sn = Order::generateOrderSn();
        // 微信支付
        $config = config('wechat.payment');
        $wechat = Factory::payment($config);
        $result = $wechat->order->unify([
            'body'         => '洗车小程序-洗车服务订单',
            'out_trade_no' => $order->order_sn,
            'total_fee'    => (int)bcmul($order->pay_amount, '100', 2),
            'notify_url'   => Env::get('app.app_host') . '/index/wechat/wechat_notify',
            'trade_type'   => 'JSAPI',
            'openid'       => $order['openid'],
        ]);
        $order->pay_type = 1;
        if ($result['return_code'] === 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
            $order->save();
            PayLog::orderPayCreate($order);
            return $wechat->jssdk->bridgeConfig($result['prepay_id'], false);
        } else {
            throw new ApiException($result['err_code_des'],404);
        }
    }


    /**
     * 组合支付
     * @param Order $order
     * @return array|string
     * @throws ApiException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function payWechatAndBalance(Order $order)
    {
        if ($order->order_status !== Order::ORDER_STATUS_WAIT_PAY)
            throw new ApiException('订单状态错误',404);
        // 需重新计算订单金额
        $order->pay_amount = $this->calculateByPayType($order,Order::PAY_TYPE_WECHAT_AND_BALANCE)['pay_amount'];
        $order->order_sn = Order::generateOrderSn();
        //获取用户余额
        $member = Member::getMember($this->memberId);
        if (bccomp((string)$member['balance'], (string)$order->pay_amount) != -1)
            throw new ApiException('该笔订单不支持组合支付',404);
        //冻结余额
//        FreezeRecord::create(['member_id'=>$this->memberId,'money'=>$member['balance'],'order_id'=>$order->id,'discount'=>$member['discount'],'status'=>1]);
        $pay_amount = bcsub($order->pay_amount, $member['balance'], 2);//需要微信支付的金额
//        $member->balance = 0;
//        $member->discount = 1;
//        $member->save();
        // 微信支付
        $config = config('wechat.payment');
        $wechat = Factory::payment($config);
        $result = $wechat->order->unify([
            'body'         => '洗车小程序-洗车服务订单',
            'out_trade_no' => $order->order_sn,
            'total_fee'    => (int)bcmul($pay_amount, '100', 2),
            'notify_url'   => Env::get('app.app_host') . '/index/wechat/wechat_notify',
            'trade_type'   => 'JSAPI',
            'openid'       => $order['openid'],
        ]);
        $order->pay_type = Order::PAY_TYPE_WECHAT_AND_BALANCE;
        $order->balance_money = $member['balance'];
        $order->wechat_money = $pay_amount;
        $order->discount = $member->discount;
        if ($result['return_code'] === 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
            $order->save();
            PayLog::orderPayCreate($order);
            return $wechat->jssdk->bridgeConfig($result['prepay_id'], false);
        } else {
            throw new ApiException($result['err_code_des'],404);
        }
    }



    /**
     * 余额支付
     * @param Order $order
     * @return void|string
     * @throws ApiException
     */
    public function payBalance(Order $order)
    {
        Db::startTrans();
        try {
            if ($order->order_status !== Order::ORDER_STATUS_WAIT_PAY)
                throw new ApiException('订单状态错误',404);
            // 需重新计算订单金额
            $order->pay_amount = $this->calculateByPayType($order,Order::PAY_TYPE_BALANCE)['pay_amount'];
            $order->pay_type = 2;
            $member = $this->handleMemberBalancePay($order); // 会员余额支付判断及扣除
            $order  = $this->updateOrder($order);      // 更新订单
            OrderCommission::addRecord($order->id);
            Db::commit();
            Queue::push(Clue::class,['member_id'=>$order->member_id,'event_type'=>2,'props'=>['pay_amount'=>intval($order['pay_amount'] * 100)]],'message');//付费
            $this->send_message($order->id);
            return '余额支付成功';
        } catch (\Throwable $e) {
            Db::rollback();

            if ($e instanceof ApiException) {
                throw $e;

            }

            Log::error($e->getMessage());
            throw new ApiException('支付失败',404);
        }
    }

    /**
     * 发送消息模板
     * @param $order_id
     * @return bool
     */
    public function send_message($order_id)
    {
        try{
            $order = Order::field('id,shop_id,order_sn,member_id,order_amount,order_status,payment_time,audit_code,pay_amount,coupon_id,coupon_money,pay_type,expires_time,createtime,agent_id')
                ->where(['order.id'=>$order_id])->with(['orderGoods', 'car','shop','coupon','aftersalesc'])->find();
            if (!$order){
                return false;
            }
            $member_list = ShopMember::where(['shop_id'=>$order['shop_id'],'is_del'=>0])->select();
            if (!empty($member_list)){
                foreach ($member_list as $v){
                    Queue::push(Message::class,[
                        'member_id'=>$v['member_id'],
                        'template_id'=>config('wechat_gzh')['gzh_template']['consumption_notice'],
                        'pagepath'=>'pages/shop/order/index',
                        'data'=>[
                            'thing2'=>$order['order_goods'][0]['goods_name'],
                            'amount5'=>$order['pay_amount'],
                            'car_number8'=>$order['car']['car_numbers'],
                            'time9'=>date('Y-m-d H:i'),
                            'character_string12'=>$order['order_sn']
                        ]
                    ],'message');
                }
            }
            return true;
        }catch (Exception $e){
            return false;
        }
    }


    /**
     * 微信支付回调
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     */
    public function wechatNotify()
    {
        $wechat = Factory::payment(config('wechat.payment'));
        return $wechat->handlePaidNotify(function ($message, $fail) use ($wechat) {
            Db::startTrans();
            try {
                $date = date('Ymd');
                $fp   = fopen(RUNTIME_PATH . "/log/log_order_notify-{$date}.php", "a");
                fwrite($fp, date('Y-m-d H:i:s') . "   " . json_encode($message) . "\r\n");
                fclose($fp);
                $order = $this->model->lock(true)->where('order_sn', $message['out_trade_no'])->find();
                if (empty($order) || $order['order_status'] !== Order::ORDER_STATUS_WAIT_PAY) {
                    return true;
                }

                if ($message['return_code'] === 'SUCCESS' && $message['result_code'] === 'SUCCESS') { // return_code 表示通信状态，不代表支付状态

                    // 再查一次微信订单确保安全
                    $res = $wechat->order->queryByOutTradeNumber($message['out_trade_no']);

                    if ($res['return_code'] === 'SUCCESS' && $res['result_code'] === 'SUCCESS' && $res['trade_state'] === 'SUCCESS') {
                        // 用户是否支付成功
                        $order = $this->updateOrder($order, Order::PAY_TYPE_WECHAT, $res['transaction_id']);      // 更新订单
                        // 会员收支记录
                        MoneyRecord::create([
                            'member_id'   => $order->member_id,
                            'type'        => MoneyRecord::TYPE_SPEND,
                            'money'       => $order->pay_amount,
                            'balance'     => model('member')->where('id', $order['member_id'])->value('balance') ?? 0,
                            'order_id'    => $order->id,
                            'detail_type' => MoneyRecord::DETAIL_TYPE_ORDER,
                            'remark'      => '订单微信支付',
                        ]);
                        PayLog::payFinish($res);
                    }

                } else {
                    return $fail('通信失败，请稍后再通知我');
                }
                Db::commit();
                return true;
            } catch (Exception $e) {
                Db::rollback();
                Log::error('支付回调处理失败' . $e->getMessage());
                return false;
            }
        });
    }

    /**
     * 更新订单
     * @param Order $order
     * @param int $payType
     * @param string $transactionId
     * @return Order
     */
    public function updateOrder(Order $order, int $payType = Order::PAY_TYPE_BALANCE, string $transactionId = ''): Order
    {
        $order->order_status   = Order::ORDER_STATUS_WAIT_AUDIT;
        $order->payment_time   = time();
        $order->pay_type       = $payType;
        $order->transaction_id = $transactionId;
        $order->expires_time = strtotime('+30 day');//订单90天内未核销自动退款
        $order->save();
        return $order;
    }

    /**
     * 处理会员余额支付
     * @param $order
     * @return array|bool|\PDOStatement|string|\think\Model|null
     * @throws ApiException
     */
    public function handleMemberBalancePay($order)
    {
        // 判断会员余额
        $member = Member::getMemberForLock($this->memberId);

        if (bccomp((string)$member['balance'], (string)$order->pay_amount) === -1)
            throw new ApiException('余额不足',404);
        $member_balance = bcsub($member->balance, $order->pay_amount, 2);
        if ($member_balance == 0){
            $member->discount = 1;
        }
        // 扣除会员余额
        $member->balance = $member_balance;
        $member->save();
        // 会员收支记录
        MoneyRecord::create([
            'member_id'   => $order->member_id,
            'type'        => MoneyRecord::TYPE_SPEND,
            'money'       => $order->pay_amount,
            'balance'     => $member->balance,
            'order_id'    => $order->id,
            'detail_type' => MoneyRecord::DETAIL_TYPE_ORDER,
            'remark'      => '订单余额支付',
        ]);
        return $member;
    }

    /**
     * 商家记录处理
     * @param $order
     * @return array|bool|\PDOStatement|string|\think\Model|null
     * @throws ApiException
     */
    public function handleShopRecord($order)
    {
        $shop = Shop::getShopForLock($order->shop_id);
        // 判断店铺余额
//        if (bccomp((string)$shop['money'], (string)$order->pay_amount) === -1) throw new ApiException('店铺余额不足');
        // 扣除店铺余额
        $shop->money = bcsub($shop->money, $order->shop_cost, 2);
        $shop->save();
        // 商家资金记录
        MoneyRecord::create([
            'type'        => MoneyRecord::TYPE_SPEND,
            'money'       => $order->shop_cost,
            'balance'     => $shop->money,
            'order_id'    => $order->id,
            'shop_id'     => $shop->id,
            'detail_type' => MoneyRecord::DETAIL_TYPE_ORDER,
            'remark'      => '商家订单成本扣除',
        ]);
        return $shop;
    }

    /**
     * 计算提交订单页面实际价格
     * @param array $params
     * @return array
     * @throws ApiException
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function calculate(array $params)
    {
        bcscale(2);
        // 店铺
        $shop = model('shop')->find($params['shop_id']);
        if (empty($shop))
            throw new ApiException('店铺不存在',404);
        // 商品
        $shopGoods = ShopGoods::get(['goods_id'=>$params['goods_id'],'shop_id'=>$params['shop_id']],['goods']);
        if (empty($shopGoods))
            throw new ApiException('商品不存在',404);

        $discount_price = ShopGoods::getPrice($shopGoods['market_price'])['price'];//获取打折后的价格
        // 获取会员折扣
//        $discount      = Member::getMemberDiscount($this->memberId);
//        $afterDiscount = bcmul($shopGoods['price'], $discount); // 折扣后价格
        // 优惠劵
        $couponMoney = "0.00";
        if (isset($params['coupon_id']) && !empty($params['coupon_id'])) {
            $coupon = Coupon::checkCoupon($params['coupon_id'], $this->memberId, $discount_price);
            if (empty($coupon)) {
                throw new ApiException('优惠劵使用错误',404);
            }
            $couponMoney = $coupon['money'];
        }

        // 计算实际支付价格
        $payAmount = bccomp($discount_price, $couponMoney) === -1 ? "0.00" : bcsub($discount_price, $couponMoney);
        return [
                'order_amount'    => $shopGoods['market_price'],                        // 订单总价
                'discount_money' => $couponMoney, // 折扣优惠金额
                'coupon_amount'   => $couponMoney,                               // 优惠劵金额
                'money'      => $payAmount,                                 // 应付金额
                'goods_info'=>$shopGoods
        ];
    }

    /**
     * 通过支付方式计算价格
     * @param $order
     * @param int $payType
     * @return mixed|string
     * @throws ApiException
     */
    public function calculateByPayType($order, int $payType = Order::PAY_TYPE_WECHAT)
    {
        try{
            $discount = 1;
            if (empty($order))
                throw new ApiException('订单不存在',404);
            if ($order['order_status'] !== Order::ORDER_STATUS_WAIT_PAY)
                throw new ApiException('订单状态错误',404);
            $member_info = Member::get($order['member_id']);//获取用户信息
            $vip_discount = Config::where(['name'=>'vip_discount'])->value('value');//vip折扣
            $member_discount = Config::getMemberDiscount();//会员折扣
            $payAmount = bcmul($order['order_amount'],$member_discount,2); // 折扣后价格
            $discount = $member_discount;
            if ($payType === Order::PAY_TYPE_WECHAT) { //微信支付
                if ($member_info['is_vip'] == 1 && $vip_discount < $member_discount){
                    $discount =  $vip_discount;
                    $payAmount = bcmul($order['order_amount'],$discount,2); // 折扣后价格
                }
                $payAmount = bcsub($payAmount, $order['coupon_money'], 2);
            }elseif($payType === Order::PAY_TYPE_WECHAT_AND_BALANCE){//组合支付
                if ($member_info['is_vip'] == 1){
                    if ($vip_discount < $member_info['discount']){
                        $discount = $vip_discount;
                    }else{
                        $discount = $member_info['discount'];
                    }
                    if ($discount > $member_discount){
                        $discount = $member_discount;
                    }
                }else{
                    if ($member_info['discount'] < $member_discount){
                        $discount = $member_info['discount'];
                    }else{
                        $discount = $member_discount;
                    }
//                    $discount = bccomp($member_info['discount'], $member_discount) === -1 ? $member_info['discount'] : $member_discount;//充值折扣与会员折扣比较哪个更优惠就用哪个
                }
                $payAmount = bcmul($order['order_amount'],$discount,2); // 折扣后价格
                $payAmount = bcsub($payAmount,$order['coupon_money'],2); // 扣掉优惠券后价格
                $payAmount = $payAmount < 0 ? 0 : $payAmount;

            } else {//余额支付
                if ($member_info['is_vip'] == 1){
                    if ($vip_discount < $member_info['discount']){
                        $discount = $vip_discount;
                    }else{
                        $discount = $member_info['discount'];
                    }
                    if ($discount > $member_discount){
                        $discount = $member_discount;
                    }
                }else{
                    if ($member_info['discount'] < $member_discount){
                        $discount = $member_info['discount'];
                    }else{
                        $discount = $member_discount;
                    }
//                    $discount = bccomp($member_info['discount'], $member_discount) === -1 ? $member_info['discount'] : $member_discount;
                }
                $payAmount = bcmul($order['order_amount'],$discount,2); // 折扣后价格
                $payAmount = bcsub($payAmount,$order['coupon_money'],2); // 扣掉优惠券后价格
                $payAmount = $payAmount < 0 ? 0 : $payAmount;

//            $payAmount     = bccomp($order['order_amount'], $order['coupon_money']) === -1 ? "0.00" : bcsub($order['order_amount'], $order['coupon_money']);
//            if ($payAmount > 0){
//                if ($member_info['is_vip'] == 1){
//                    $discount = bccomp($vip_discount, $member_info['discount']) === -1 ? $vip_discount : $member_info['discount'];
//                }else{
//                    $discount = $member_info['discount'];
//                }
//                $payAmount = bcmul($payAmount,$discount); // 折扣后价格
//            }
//            $payAmount = $payAmount < 0.01 ? 0.01 : $payAmount;
            }
            if ($payAmount < 0.01)
                $payAmount=0;
            return ['pay_amount' => sprintf("%.2f",$payAmount),'discount'=>sprintf("%.2f",$discount),'pay_type'=>$payType,'balance'=>$member_info['balance']];
        }catch (Exception $e){
            throw new ApiException($e->getMessage(),404);
        }

    }

    /**
     * 退款详情
     * @param $params
     * @return bool
     * @throws ApiException
     */
    public function refundDetail($params)
    {
        $info = OrderAftersales::get(['order_id'=>$params['order_id'],'member_id'=>MemberVo::instance()->getMemberId()],['orderAftersalesRecord'=>function($query){$query->field('id,order_aftersales_id,status,remark,createtime');}]);
        if (empty($info))
            throw new ApiException('无该订单退款记录信息',404);
        unset($info['order_amount'],$info['createtime'],$info['updatetime'],$info['transaction_id'],$info['agent_id']);
        return $info;

    }


    /**
     * 申请退款
     * @param $params
     * @return bool
     * @throws ApiException
     */
    public function applyRefund($params)
    {
        Db::startTrans();
        try{
            $order = Order::get(['id'=>$params['order_id'],'member_id'=>MemberVo::instance()->getMemberId()]);
            if (empty($order))
                throw new Exception('订单信息不存在');
            if ((int)$order['order_status'] !== Order::ORDER_STATUS_WAIT_AUDIT)
                throw new Exception('待核销订单才可申请退款');
            $order->order_status      = Order::ORDER_STATUS_REFUND;
            $order->refund_apply_time = time();
            $order->save();
            //查看之前是否有申请过
            $res = OrderAftersales::get(['order_id'=>$order['id'], 'shop_id'=>$order['shop_id'], 'member_id'=>$order['member_id']]);
            if ($res){
                $res->status = OrderAftersales::STATUS_WAIT_AUDIT;
                $res->reason = $params['reason'];
                $res->save();
            }else{
                $res = OrderAftersales::create([
                    'order_id'=>$order['id'],
                    'shop_id'=>$order['shop_id'],
                    'member_id'=>$order['member_id'],
                    'order_amount'=>$order['order_amount'],
                    'status'=>OrderAftersales::STATUS_WAIT_AUDIT,
                    'refund'=>$order['pay_amount'],
                    'pay_type'=>$order['pay_type'],
                    'transaction_id'=>$order['transaction_id'],
                    'agent_id'=>$order['agent_id'],
                    'reason'=>$params['reason'],
                ]);
            }
            OrderAftersalesRecord::create(['order_id'=>$order['id'],'order_aftersales_id'=>$res->id]);
            \app\common\model\Message::create(['content'=>"用户发起一笔退款申请，订单号：{$order['order_sn']}，请及时查看！"]);//发送站内信
            Db::commit();
            $admins = Admin::where(['status'=>'normal','member_id'=>['gt',0]])->select();
            foreach ($admins as $v){
                Queue::push(\app\job\Message::class,[
                    'member_id'=>$v['member_id'],
                    'template_id'=>config('wechat_gzh')['gzh_template']['apply_refund'],
                    'data'=>[
                        'character_string1'=>$order['order_sn'],
                        'time2'=>date('Y-m-d H:i'),
                    ]
                ],'message');
            }
            return true;
        }catch (Exception $e){
            Db::rollback();
            throw new ApiException($e->getMessage(),404);
        }
    }








    /**
     * 申请退款
     * @param array $params
     * @return string
     * @throws ApiException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function applyRefund_back(array $params): string
    {
        $order = $this->orderExist($params['order_id']);
        if ((int)$order['order_status'] !== Order::ORDER_STATUS_WAIT_AUDIT) {
            throw new ApiException('待核销订单才可申请退款',404);
        }
        $order->order_status      = Order::ORDER_STATUS_REFUND;
        $order->refund_apply_time = time();
        $order->save();

        bcscale(2);
        $member = Member::getMemberForLock($this->memberId);
        if ((int)$order['pay_type'] === Order::PAY_TYPE_BALANCE) { // 退回余额
            $member->balance = bcadd($member->balance, $order->pay_amount);
            $member->save();
        }elseif ((int)$order['pay_type'] === Order::PAY_TYPE_WECHAT_AND_BALANCE){ //组合支付
            if ($member->discount > $order->discount){//如果折扣比目前低，则更新
                $member->discount = $order->discount;
            }
            $member->balance = bcadd($member->balance,$order->balance_money,2);//余额加回去
            $member->save();
            $totalFee = bcmul($order->wechat_money, '100');
            $wechat   = Factory::payment(config('wechat.payment'));
            $result   = $wechat->refund->byTransactionId($order->transaction_id, $order->order_sn, $totalFee, $totalFee, ['refund_desc' => '客户申请退款']);
            if ($result['return_code'] !== 'SUCCESS' || $result['result_code'] !== 'SUCCESS') {
                throw new ApiException('退款失败:' . $result['err_code_des'] ?? $result['return_msg'],404);
            }
        } else { // 微信原路退回
            $wechat   = Factory::payment(config('wechat.payment'));
            $totalFee = bcmul($order->pay_amount, '100');
            $result   = $wechat->refund->byTransactionId($order->transaction_id, $order->order_sn, $totalFee, $totalFee, ['refund_desc' => '客户申请退款']);
            if ($result['return_code'] !== 'SUCCESS' || $result['result_code'] !== 'SUCCESS') {
                throw new ApiException('退款失败:' . $result['err_code_des'] ?? $result['return_msg'],404);
            }
        }
        MoneyRecord::create([
            'member_id'   => $order->member_id,
            'type'        => MoneyRecord::TYPE_INCOME,
            'money'       => $order->pay_amount,
            'balance'     => $member->balance,
            'order_id'    => $order->id,
            'detail_type' => MoneyRecord::DETAIL_TYPE_REFUND,
            'remark'      => '订单退款',
        ]);

        return '提交申请成功';
    }

    /**
     * 订单数量
     * @return array
     * @throws Exception
     */
    public function orderNum()
    {
        return [
            'total' => Order::orderNum(),
            'audit' => Order::orderNum(2),
        ];
    }

    /**
     * 核销订单
     * @param array $params
     * @return bool
     * @throws ApiException
     */
    public function useOrder(array $params): bool
    {
        try{
            $order = $this->model->where([
                'audit_code' => $params['audit_code'],
                'shop_id'    => $this->shopId
            ])->find();

            if(empty($order) || (int)$order['order_status'] !== Order::ORDER_STATUS_WAIT_AUDIT) throw new ApiException('订单状态异常',404);

            // 核销订单修改
            $order->order_status = Order::ORDER_STATUS_WAIT_COMMENT;
            $order->audit_time = time();
            $order->save();
            $days = intval(Env::get('app.days',180));
            $days = $days-1;
            $service_times = Order::whereBetween('audit_time',[strtotime(date('Y-m-d',strtotime("-{$days} days"))),time()])->where(['member_id'=>$order->member_id])->whereIn('order_status',[3,4])->count('id');//当前时间往前推180的总完成数
            Log::info($service_times);
            $service_num = Config::where(['name'=>'service_num'])->value('value');//系统设置的达标次数
            Log::info($service_num);
            if ($service_times >= $service_num){ //成为VIP 或者延长
                Log::info(6666666);
                Member::update(['is_vip'=>1],['id'=>$order->member_id]);//更改用户为vip
                $service_info = ServiceTimes::where(['member_id'=>$order->member_id])->find();
                $end_time = strtotime(date('Y-m-d 23:59:59',strtotime("+{$days} days")));
                if ($service_info){
                    if ($service_info->end_time <$end_time){
                        $service_info->end_time = $end_time;
                    }
                    $service_info->is_vip = 1;
                    $service_info->save();
                }else{
                    ServiceTimes::create(['member_id'=>$order->member_id,'begin_time'=>time(),'end_time'=>$end_time,'is_vip'=>1]);
                }
            }
            Log::info(7777777777);

            // 扣除商家成本价及记录
            $this->handleShopRecord($order);

            return true;
        }catch (Exception $e){
            return false;
        }

    }


    /**
     * 订单支付方式信息
     * @param $params
     * @return mixed
     * @throws ApiException
     * @throws \think\exception\DbException
     */
    public function orderPayMethodInfo($params)
    {
        $order_info = Order::get($params['order_id']);
        if (empty($order_info))
            throw new ApiException('订单信息不存在',404);
        if((int)$order_info['order_status'] !== Order::ORDER_STATUS_WAIT_PAY)
            throw new ApiException('订单状态异常',404);
        $data['shop_name'] = model('shop')->where('id',$order_info['shop_id'])->value('shop_name');//店铺名称
        $data['goods_name'] = model('order_goods')->where('order_id',$order_info['id'])->value('goods_name');//商品名称

        //余额支付
        $balance = $this->calculateByPayType($order_info,Order::PAY_TYPE_BALANCE);
        $balance['enough'] = bccomp($balance['balance'], $balance['pay_amount'],2) === -1 ? 0 : 1;
        $balance['discount'] = $balance['discount'] * 10;
        $balance['name'] = '账户支付';
        $balance['icon'] = 'red-packet-fill';
        $data['method'][] =$balance;


        //微信支付
        $wechat = $this->calculateByPayType($order_info,Order::PAY_TYPE_WECHAT);
        if ($wechat['pay_amount'] != 0){
            $wechat['enough'] = 1;
            $wechat['name'] = '微信支付';
            $wechat['discount'] = $wechat['discount'] * 10;
            $wechat['icon'] = 'weixin-circle-fill';
            $data['method'][] = $wechat;
        }




        if ($balance['balance'] > 0 && $balance['balance'] < $balance['pay_amount']){
            //组合支付
            $zh_pay = $this->calculateByPayType($order_info,Order::PAY_TYPE_WECHAT_AND_BALANCE);
            $zh_pay['enough'] = 1;
            $zh_pay['name'] = '组合支付';
            $zh_pay['discount'] = $zh_pay['discount'] * 10;
            $zh_pay['icon'] = 'rmb-circle-fill';
            $data['method'][] = $zh_pay;
        }




//        if ($balance['enough'] == 1){ //余额足够
//            $data['method'][] =$balance;
//        }else{
//            //组合支付
//            $zh_pay = $this->calculateByPayType($order_info,Order::PAY_TYPE_WECHAT_AND_BALANCE);
//            $zh_pay['enough'] = 1;
//            $zh_pay['name'] = '组合支付';
//            $data['method'][] = $zh_pay;
//        }







        return $data;
    }


    /**
     * 生成二维码
     * @param string $url [字符]
     * @param  [type] $is_save [是否保存]
     * @param  [type] $pid     [唯一标识符]
     * @return string  [type]  [返回图片标签字符串]
     */
    public function mkCode($url,$name)
    {
        $Writer = new PngWriter();
        $qrCode = QrCode::create($url)//跳转的url地址
        ->setEncoding(new Encoding('UTF-8'))    //设置编码格式
        ->setErrorCorrectionLevel(new ErrorCorrectionLevelLow())    //设置纠错级别为低
        ->setSize(190)      //大小
        ->setMargin(5)     //边距
        ->setRoundBlockSizeMode(new RoundBlockSizeModeMargin())     //设置圆轮大小边距
        ->setForegroundColor(new Color(0, 0, 0))        //前景色
        ->setBackgroundColor(new Color(255, 255, 255));       //背景色
        $logo = Logo::create("uploads/static/logo2.jpg")
            ->setResizeToWidth(30);
        $result = $Writer->write($qrCode, $logo);
        header('Content-Type: '.$result->getMimeType());
        $result->getString();
        $file_path = 'uploads/order_qrcode/';
        if(!file_exists($file_path)){
            mkdir($file_path,0777,true);
        }
        $qrcode= $name.'.png';   //二维码文件名称,mt_rand()运行速度要比rand()快很多
        $result->saveToFile($file_path.$qrcode);
    }

    public function refund($order_id)
    {
        Db::startTrans();
        try{
            $order = Order::get($order_id);
            if ($order['order_status'] !== Order::ORDER_STATUS_REFUND)
                return false;
            OrderCommission::update(['status'=>2],['order_id'=>$order_id]);
            //判断是否有使用优惠券
            if ($order['coupon_id'] !==0){
                Coupon::where('id',$order['coupon_id'])->setField('status',1);
            }
            if ($order['pay_type'] == 1){ //微信支付方式
                $wechat   = Factory::payment(config('wechat.payment'));
                $totalFee = bcmul($order->pay_amount, '100');
                $result   = $wechat->refund->byTransactionId($order->transaction_id, $order->order_sn, $totalFee, $totalFee, ['refund_desc' => '客户申请退款']);
                if ($result['return_code'] !== 'SUCCESS' || $result['result_code'] !== 'SUCCESS') {
                    Log::info('退款失败:' . $result['err_code_des'] ?? $result['return_msg']);
                    return false;
                }
            }elseif ((int)$order['pay_type'] === Order::PAY_TYPE_WECHAT_AND_BALANCE){ //组合支付
                $member = Member::get($order->member_id);
                if ($member->discount > $order->discount){//如果折扣比目前低，则更新
                    $member->discount = $order->discount;
                }
                $member->balance = bcadd($member->balance,$order->balance_money,2);//余额加回去
                MoneyRecord::create(['member_id'=> $order->member_id,'type'=> MoneyRecord::TYPE_INCOME, 'money'=> $order->pay_amount, 'balance'=> $member->balance, 'order_id' => $order->id, 'detail_type' => MoneyRecord::DETAIL_TYPE_REFUND, 'remark'=> '组合支付订单退款']);
                $member->save();
                $wechat   = Factory::payment(config('wechat.payment'));
                $totalFee = bcmul($order->wechat_money, '100');
                $result   = $wechat->refund->byTransactionId($order->transaction_id, $order->order_sn, $totalFee, $totalFee, ['refund_desc' => '客户申请退款']);
                if ($result['return_code'] !== 'SUCCESS' || $result['result_code'] !== 'SUCCESS') {
                    Log::info('退款失败:' . $result['err_code_des'] ?? $result['return_msg']);
                    return false;
                }
            }else{//余额支付方式
                $member = Member::get($order->member_id);
                $member->balance = bcadd($member->balance, $order->pay_amount,2);
                MoneyRecord::create(['member_id'=> $order->member_id,'type'=> MoneyRecord::TYPE_INCOME, 'money'=> $order->pay_amount, 'balance'=> $member->balance, 'order_id' => $order->id, 'detail_type' => MoneyRecord::DETAIL_TYPE_REFUND, 'remark'=> '订单退款']);
                $member->balance_show_drop = 1;
                $member->save();
            }
            Db::commit();
           return true;
        }catch (Exception $e){
            Db::rollback();
            return false;
        }


    }

}